﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SnakeWalk.Utils;

namespace SnakeWalk
{
    public class GameSnake
    {
        // Game Instance
        public GameSnake(SWSize sizePanel)
        {
            this.sizePanel = sizePanel;
        }
        
        // Manage Snake
        public Snake Snake { get; private set; }
        public Bait Bait { get; private set; }
        public DirectionSnake Direction { get; set; }
        public GameSate GameStateSnake { get; set; }
        public int GameScore { get; set; }
        Random randomBait = new Random();
        private SWSize sizePanel;

        public void NewGame()
        {
            // Create First Snake 
            int FistCountBodySnake = (int)Optional.FirstSnake;
            Snake = new Snake(FistCountBodySnake);

            SWSize sizeBody = new SWSize((int)SizeAndBaitSnake.Width, (int)SizeAndBaitSnake.Height);

            // Create Head Snake
            Snake.SnakeBodies.Add(new Body(new SWPosition(FistCountBodySnake * sizeBody.Width, 3 * sizeBody.Height), sizeBody));

            // Create Body Snake
            int j = FistCountBodySnake - 1;
            for (int i = 0; i < FistCountBodySnake - 1; i++)
            {
                Snake.SnakeBodies.Add(new Body(new SWPosition(j * sizeBody.Width, 3 * sizeBody.Height), sizeBody));
                j--;
            }

            // Default Direction
            Direction = DirectionSnake.Down;

            // Random Bait
            Bait = new Bait();
            RandomBait();
        }

        private void RandomBait()
        {
            int i = sizePanel.Width / (int)SizeAndBaitSnake.Width;
            int j = sizePanel.Height / (int)SizeAndBaitSnake.Height;

            int positionX = randomBait.Next(0, i) * (int)SizeAndBaitSnake.Width;
            int positionY = randomBait.Next(0, j) * (int)SizeAndBaitSnake.Height;

            //Bait = new Bait(new SWPosition(positionX, positionY), new SWSize((int)SizeAndBaitSnake.Width, (int)SizeAndBaitSnake.Height));
            Bait.Position = new SWPosition(positionX, positionY);
            Bait.Size =  new SWSize((int)SizeAndBaitSnake.Width, (int)SizeAndBaitSnake.Height);
        }

        public void Run()
        {
            Snake.Move(Direction);

            CheckGameOver();

            // Validate Eat Bait
            if (ValidateEatBait())
            {
                EatBait();
                GameScore++;
                if (CheckWin())
                {
                    StopGame(true);
                }
                else
                {
                    RandomBait();
                }
            }
        }

        private bool CheckWin()
        {
            if (GameScore == (int)Optional.WinScore)
            {
                return true;
            }
            return false;
        }

        private bool ValidateEatBait()
        {
            Body headSnake = Snake.SnakeBodies[0];
            if (headSnake.Position.X == Bait.Position.X && headSnake.Position.Y == Bait.Position.Y)
            {
                return true;
            }
            return false;
        }

        private void EatBait()
        {
            Body newBody = new Body();
            Body endBody = Snake.SnakeBodies[Snake.SnakeBodies.Count - 1];
            switch (Direction)
            {
                case DirectionSnake.Up:
                    newBody = new Body(new SWPosition(endBody.Position.X, endBody.Position.Y + (int)SizeAndBaitSnake.Height), endBody.Size);
                    break;
                case DirectionSnake.Down:
                    newBody = new Body(new SWPosition(endBody.Position.X, endBody.Position.Y - (int)SizeAndBaitSnake.Height), endBody.Size);
                    break;
                case DirectionSnake.Left:
                    newBody = new Body(new SWPosition(endBody.Position.X + (int)SizeAndBaitSnake.Width, endBody.Position.Y), endBody.Size);
                    break;
                case DirectionSnake.Right:
                    newBody = new Body(new SWPosition(endBody.Position.X - (int)SizeAndBaitSnake.Width, endBody.Position.Y), endBody.Size);
                    break;
                default:
                    newBody = new Body();
                    break;
            }
            Snake.SnakeBodies.Add(newBody);
        }

        private void CheckGameOver()
        {
            Body headSnake = Snake.SnakeBodies[0];
            // Boundary
            if (headSnake.Position.X < 0 | headSnake.Position.Y < 0
                | headSnake.Position.X + (int)SizeAndBaitSnake.Width >= sizePanel.Width 
                | headSnake.Position.Y + (int)SizeAndBaitSnake.Height >= sizePanel.Height)
            {
                GameStateSnake = GameSate.GameOver;
            }

            // Touch itself
            for (int i = 1; i < Snake.SnakeBodies.Count; i++)
            {
                if (headSnake.Position.X == Snake.SnakeBodies[i].Position.X && headSnake.Position.Y == Snake.SnakeBodies[i].Position.Y)
                {
                    GameStateSnake = GameSate.GameOver;
                }
            }
        }

        public void ChangeDirection(DirectionSnake directionSnake)
        {
            if (ValidateDirection(directionSnake))
            { 
                Direction = directionSnake;
            }
        }

        private bool ValidateDirection(DirectionSnake directionSnake)
        {
            bool regular = true;
            switch (directionSnake)
            {
                case DirectionSnake.Up:
                    if (Direction == DirectionSnake.Down)
                    {
                        regular = false;
                    }
                    break;
                case DirectionSnake.Down:
                    if (Direction == DirectionSnake.Up)
                    {
                        return false;
                    }
                    break;
                case DirectionSnake.Left:
                    if (Direction == DirectionSnake.Right)
                    {
                        return false;
                    }
                    break;
                case DirectionSnake.Right:
                    if (Direction == DirectionSnake.Left)
                    {
                        return false;
                    }
                    break;
                default:
                    break;
            }
            return regular;
        }

        public void StopGame(bool win)
        {
            if (win)
            {
                GameStateSnake = GameSate.Win;
                return;
            }
            GameStateSnake = GameSate.Stop;
        }
    }
}
